package net.chrisrichardson.cloudtools.maven.plugins;

import groovy.lang.GroovyShell;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.chrisrichardson.ec2deployer.cluster.ClusterManager;
import net.chrisrichardson.ec2deployer.cluster.ClusterSpec;

import org.apache.maven.plugin.MojoExecutionException;

/**
 * Goal which fires up the EC2 cluster
 * 
 * @goal deploy
 * 
 */
public class DeployMojo extends AbstractCloudToolsMojo {

  /**
   * @parameter expression="m1.small"
   * @required
   */
  private String instanceType;
  /**
   * @parameter
   * @required
   */
  protected String schemaName;
  /**
   * @parameter
   * @required
   */
  protected List<String> schemaUsers;
  /**
   * @parameter
   */
  protected List<String> sqlScripts;
  /**
   * @parameter expression="0"
   * @required
   */
  private int numberOfMySqlSlaves;
  /**
   * @parameter expression="1"
   * @required
   */
  private int numberOfTomcats;
  /**
   * @parameter expression="0"
   * @required
   */
  private int numberOfTerracottaHosts;
  /**
   * @parameter expression="${project.build.finalName}"
   * @required
   */
  protected String warName;
  /**
   * Parent directory of the web application
   * 
   * @parameter expression="${project.build.directory}"
   * @required
   */
  protected File outputDirectory;
  /**
   * Path to the web application
   * 
   * @parameter
   */
  protected String warDirectory;
  /**
   * 
   * @parameter
   * @required
   */
  protected String catalinaOptsBuilder;

  /**
   * Cluster topology.
   * 
   * @parameter expression="${cloudtools.topology}"
   */
  protected String topology;

  /**
   * Groovy script for additional options
   * 
   * @parameter
   */
  protected String script;

  /**
   * SSL Key file
   * 
   * @parameter
   */
  protected File sslKeyFile;

  /**
   * SSL cert file
   * 
   * @parameter
   */
  protected File sslCertFile;

  /**
   * Path to static content directory
   * 
   * @parameter
   */
  protected File staticContentPath;

  /**
   * Name of S3 bucket
   * 
   * @parameter
   */
  protected String staticContentBucket;
  
  /**
   * ebs volume id
   * 
   * @parameter expression="${cloudtools.ebs.volume}"
   */
  protected String ebsVolumeId;

  /**
   * ebs snapshot id
   * 
   * @parameter expression="${cloudtools.ebs.snapshot}"
   */
  protected String ebsSnapshotId;

  /**
   * ebs device 
   * 
   * @parameter expression="${cloudtools.ebs.device}"
   */
  protected String ebsDevice;

  /**
   * ebs volume size
   * 
   * @parameter expression="${cloudtools.ebs.volume.size}
   */
  protected Integer ebsVolumeSize;

  protected void validateParameters() throws MojoExecutionException {
    verifyFileExists(awsPropertiesFile);
    // instanceType
    if (sqlScripts != null) {
      for (String script : sqlScripts) {
        verifyFileExists(new File(script));
      }
    }
    if (warDirectory == null)
      verifyFileExists(new File(outputDirectory, warName));
    else {
      // TODO some validation
    }
  }

  private void verifyFileExists(File file) throws MojoExecutionException {
    if (!file.exists())
      throw new MojoExecutionException("Non-existent file: "
          + file.getAbsolutePath());
  }

  protected Map<String, String> getSchemaUsers() throws MojoExecutionException {
    Map<String, String> result = new HashMap<String, String>();
    for (String user : schemaUsers) {
      String[] idAndPassword = user.split(":");
      if (idAndPassword.length != 2)
        throw new MojoExecutionException(
            "Invalid user and password, should be userId:password  " + user);
      result.put(idAndPassword[0], idAndPassword[1]);
    }
    return result;
  }

  protected ClusterSpec makeClusterSpec() throws MojoExecutionException {
    ClusterSpec clusterSpec = new ClusterSpec();
    clusterSpec.instanceType(instanceType);
    clusterSpec.schema(schemaName, getSchemaUsers(), sqlScripts);
    clusterSpec.slaves(numberOfMySqlSlaves);
    clusterSpec.tomcats(numberOfTomcats);
    clusterSpec.terracottaHosts(numberOfTerracottaHosts);
    if (sslKeyFile != null || sslCertFile != null) {
      verifyFileExists(sslKeyFile);
      verifyFileExists(sslCertFile);
      clusterSpec.ssl(sslKeyFile.getAbsolutePath(), sslCertFile
          .getAbsolutePath());
    }
    if (staticContentBucket != null || staticContentPath != null) {
      verifyDirectoryExists(staticContentPath);
      if (staticContentBucket == null)
        throw new MojoExecutionException("staticContentBucket cannot be null ");
      clusterSpec.staticContent(staticContentPath.getAbsolutePath(), staticContentBucket);
    }
    if (warDirectory != null)
      clusterSpec.webApp(warDirectory, warName);
    else
      clusterSpec.webApp(new File(outputDirectory, warName).getAbsolutePath(),
          warName);
    clusterSpec.catalinaOptsBuilder(catalinaOptsBuilder);
    if (topology != null)
      clusterSpec.topology(topology);
    
    if (ebsVolumeId != null)
      clusterSpec.withExistingEbsVolume(ebsVolumeId, ebsDevice);
    else if (ebsSnapshotId != null) 
      clusterSpec.withEbsVolumeFromSnapshot(ebsSnapshotId, ebsVolumeSize, ebsDevice);
    else if (ebsDevice != null)
      clusterSpec.withNewEbsVolume(ebsVolumeSize, ebsDevice);

    if (script != null) {
      GroovyShell shell = new GroovyShell();
      shell.getContext().setVariable("clusterSpec", clusterSpec);
      shell.evaluate(script);
    }
    return clusterSpec;
  }

  private void verifyDirectoryExists(File directory)
      throws MojoExecutionException {
    if (!directory.exists() || !directory.isDirectory())
      throw new MojoExecutionException("Non-existent directory: "
          + directory.getAbsolutePath());
  }

  public void execute() throws MojoExecutionException {

    validateParameters();

    ClusterManager manager = makeClusterManager();
    // TODO - we should probably check to see whether the cluster is already
    // running
    manager.defineCluster(getClusterName(), makeClusterSpec());
    manager.startCluster(getClusterName());
  }
}
